package com.northchurchcolumbus.podcast.ncpodcaster;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;

import com.northchurchcolumbus.podcast.ncpodcaster.Uploader.UploaderProgressListener;

public class NCPodcasterGUI extends JFrame implements ActionListener
{
    
    public static class EscapableJDialog extends JDialog
    {
        public EscapableJDialog(JFrame parent)
        {
            super(parent);
        }
        
        @Override
        protected JRootPane createRootPane() {
            KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
            JRootPane rootPane = new JRootPane();
            rootPane.registerKeyboardAction(new ActionListener() {
                public void actionPerformed(ActionEvent actionEvent) {
                    setVisible(false);
                 }
               }, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
            return rootPane;
          }
    }
    private static final String FTP_SERVER_CTX_NAME = "ftp_server";
    private static final String FTP_USER_CTX_NAME="ftp_username";
    private static final String FTP_PASS_CTX_NAME="ftp_password";
    private static final String BLOGGER_ID_CTX_NAME = "blog_id";
    private static final String BLOGGER_USER_CTX_NAME="blog_username";
    private static final String BLOGGER_PASS_CTX_NAME="blog_password";
    private static final String URL_PREFIX_CTX_NAME="urlPrefix";
    private static final String LAME_PATH_CTX_NAME="lame_path";

    private static final File libdir = new File(System.getProperty("user.home"), "Library");
    private static final File prefsDir = new File(libdir, "ncpodcaster");
    private final File prefsFile = new File(prefsDir, "preferences.txt");
    private final File promptFile = new File(prefsDir, "lastPromptValues.txt");

    JTextField seriesTitleField = new JTextField(20);
    JTextField sermonTitleField = new JTextField(20);
    JTextField speakerField = new JTextField(20);
    JTextField dateField = new JTextField(2);
    JLabel filenameField = new JLabel("No file selected");
    JButton publishButton = new JButton("Publish");
    JLabel lengthField = new JLabel("00:00");
    JLabel samplerateField = new JLabel("");
    JCheckBox isSeries = new JCheckBox("Sermon Series: ");
    JMenuItem browseItem = new JMenuItem("Browse...", 'c');

    private static final String DRAFT_TYPE="Draft";
    private static final String IMMEDIATE_TYPE="Immediate";

    
    String[] publishTypes = {IMMEDIATE_TYPE, DRAFT_TYPE};
    JComboBox typeList = new JComboBox(publishTypes);
    
    File mp3File;
       
   
    public static void main(String[] args) throws Exception
    {
        NCPodcasterGUI frame = new NCPodcasterGUI();
        frame.setup();
    }
    
    public void setup()
    {        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("northChurch Podcaster");
        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());
        JPanel promptingPane = new JPanel();
        promptingPane.setLayout(new GridBagLayout());

        GridBagConstraints c = new GridBagConstraints();
        c.anchor=GridBagConstraints.WEST;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridwidth=1;
        c.gridy=0;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(8, 8, 0, 8);
        promptingPane.add(new JLabel("MP3 File:"),c);

        c.gridx++;
        c.weightx=1;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(filenameField, c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(8, 8, 0, 8);
        promptingPane.add(new JLabel("Length:"),c);
                
        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(lengthField,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("Sample Rate:"),c);
                
        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(samplerateField,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.gridwidth=1;
        c.insets = new Insets(8, 8, 0, 8);        
        promptingPane.add(new JLabel("Sermon Date:"),c);
                
        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(dateField,c);
        
        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);        
        promptingPane.add(isSeries,c);

        c.gridx++;
        c.weightx=1;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(seriesTitleField,c);
        
        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(8, 8, 0, 8);        
        promptingPane.add(new JLabel("Sermon Title:"),c);

        c.gridx++;
        c.weightx=1;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(sermonTitleField,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(8, 8, 0, 8);        
        promptingPane.add(new JLabel("Sermon Speaker:"),c);

        c.gridx++;
        c.insets = new Insets(8, 0, 0, 8);
        c.weightx=1;
        promptingPane.add(speakerField,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(8, 8, 0, 8);        
        promptingPane.add(new JLabel("Type:"),c);

        c.gridx++;
        c.insets = new Insets(8, 0, 0, 8);
        c.weightx=1;
        promptingPane.add(typeList,c);
        
        
        c.gridx=1;
        c.gridy++;
        c.insets = new Insets(8, 0, 8, 8);
        c.weightx=0;
        c.fill = GridBagConstraints.NONE;
        c.anchor=GridBagConstraints.EAST;
        promptingPane.add(publishButton,c);
        
        JMenuBar bar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        browseItem.addActionListener(this);
        bar.add(fileMenu);
        fileMenu.add(browseItem);
        this.setJMenuBar(bar);
        
        contentPane.add(promptingPane, BorderLayout.CENTER);
        
        setupActions();
        handleSeriesCheck();
        publishButton.setEnabled(false);
        filenameField.setEnabled(false);
        lengthField.setEnabled(false);
        samplerateField.setEnabled(false);

        Calendar lastSunday = Calendar.getInstance();
        //set the calendar to the last sunday.
        lastSunday.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        dateField.setText(String.format("%1$tm/%1$td/%1$tY",lastSunday));
        //Display the window.
        pack();
        setResizable(false);

        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        int X = (screen.width / 2) - (this.getWidth() / 2); // Center horizontally.
        int Y = (screen.height / 2) - (this.getHeight() / 2); // Center vertically.
        setLocation(X, Y);
        loadLastPromptValues();
        setVisible(true);
        
        doBrowse();
    }
    
    private void setupActions()
    {
        publishButton.addActionListener(this);
        isSeries.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource()==browseItem)
        {
            doBrowse();
        }
        if(e.getSource()==publishButton)
        {
            doPublish();
        }
        if(e.getSource()==isSeries)
        {
            handleSeriesCheck();
        }
    }
    
    private void handleSeriesCheck()
    {
        boolean enabled = isSeries.isSelected();
        seriesTitleField.setEnabled(enabled);
    }
    private boolean verifyFields()
    {
        if(speakerField.getText().trim().length()==0)
        {
            JOptionPane.showMessageDialog(this, "The speaker field cannot be empty", "Podcast Error", JOptionPane.ERROR_MESSAGE);
            speakerField.requestFocus();
            return false;
        }
        if(sermonTitleField.getText().trim().length()==0)
        {
            JOptionPane.showMessageDialog(this, "The sermon title field cannot be empty", "Podcast Error", JOptionPane.ERROR_MESSAGE);
            sermonTitleField.requestFocus();
            return false;
        }
        if(isSeries.isSelected() && seriesTitleField.getText().trim().length()==0)
        {
            JOptionPane.showMessageDialog(this, "The series title field cannot be empty", "Podcast Error", JOptionPane.ERROR_MESSAGE);
            seriesTitleField.requestFocus();
            return false;
        }
        
        return true;
    }
    private Calendar getCalFromDate()
    {
        String date = dateField.getText();
        String[] dateParts = date.split("/");
        if(dateParts.length!=3 && dateParts.length!=2)
        {
            return null;
        }
        try
        {
            int month=Integer.parseInt(dateParts[0]);
            int day=Integer.parseInt(dateParts[1]);
            if(month >12 || month < 0)
            { 
                throw new NumberFormatException("month");
            }
            if( day >31 || day < 0)
            { 
                throw new NumberFormatException("day");
            }
            Calendar c = Calendar.getInstance();


            int year=c.get(Calendar.YEAR);
            if(dateParts.length==3)
            {
                year=Integer.parseInt(dateParts[2]);
                if( year < 0)
                { 
                    throw new NumberFormatException("year");
                }
            }
            c.set(year, month-1, day);

            return c;
        }
        catch(NumberFormatException e)
        {
            return null;
        }
        
    }
    
    private void doPublish()
    {
        if(!verifyFields())
        {
            return;
        }
        final Calendar sermonDate = getCalFromDate();
        if(sermonDate==null)
        {
            JOptionPane.showMessageDialog(this, "The sermon date must be in the form mm/dd/yyyy", "Sermon Date Error", JOptionPane.ERROR_MESSAGE);
            dateField.requestFocus();
            return;
        }
        final JProgressBar progress = new JProgressBar(JProgressBar.HORIZONTAL, 0, 100);
        final JLabel progressTitle = new JLabel("Starting...");
        final AtomicBoolean isCancelled = new AtomicBoolean(false);
        final AtomicBoolean isDone = new AtomicBoolean(false);

        JButton cancelButton = new JButton("Cancel");
        cancelButton.addActionListener(new ActionListener()
        {

            public void actionPerformed(ActionEvent e)
            {
                isCancelled.set(true);                
                progressTitle.setText("Cancelling...");
            }
            
        });
        
        final JDialog dialog = new JDialog(this)
        {
            public void dispose()
            {
                if(!isDone.get())
                {
                    isCancelled.set(true);
                    progressTitle.setText("Cancelling...");
                }
                super.dispose();
            }
        };
        dialog.setTitle("Podcasting...");

        dialog.setModal(true);
        JPanel panel = new JPanel();
        
        panel.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.anchor=GridBagConstraints.NORTHWEST;
        c.gridx=0;
        c.gridy=0;
        c.gridwidth=2;
        c.weightx=1;
        c.insets = new Insets(8, 8, 0, 8);
        panel.add(progressTitle, c);

        c.gridwidth=1;
        c.gridy++;
        c.insets = new Insets(8, 8, 8, 8);
        panel.add(progress, c);

        c.weightx=0;
        c.gridx++;
        c.insets = new Insets(8, 0, 8, 8);
        panel.add(cancelButton , c);
        dialog.setContentPane(panel);
        dialog.setDefaultCloseOperation(
                JDialog.DISPOSE_ON_CLOSE);
        dialog.pack();
        

        dialog.setResizable(false);
        dialog.setLocation((int)this.getLocation().getX() + this.getWidth()/2 - dialog.getWidth()/2,
                (int)this.getLocation().getY() + this.getHeight()/2 - dialog.getHeight()/2);
        
        //Create the podcaster and do the update.
        Thread t = new Thread()
        {
            public void run()
            {
                final AtomicInteger stage=new AtomicInteger(0);

                String selectedType = publishTypes[typeList.getSelectedIndex()];
                final boolean isDraft=selectedType==DRAFT_TYPE;
                try
                {
                    StringBuilder titleText = new StringBuilder(sermonTitleField.getText());
                    if(isSeries.isSelected())
                    {
                        titleText.insert(0, ": ");
                        titleText.insert(0, seriesTitleField.getText());
                    }
                    progressTitle.setText("Copying to Local File...");
                    File tempSourceFile = copyToLocalTempFile();
                    progress.setValue(stage.addAndGet(20));

                    final NCPodcaster podcaster = new NCPodcaster(getContext(), tempSourceFile, sermonDate, titleText.toString(), speakerField.getText());
                    progressTitle.setText("Encoding...");
                    podcaster.encode();
                    if(isCancelled.get())
                    {
                        return;
                    }
                    progress.setValue(stage.addAndGet(20));
                    progressTitle.setText("Tagging...");
                    podcaster.tag();
                    if(isCancelled.get())
                    {
                        return;
                    }
                    progress.setValue(stage.addAndGet(20));
                    progressTitle.setText("Uploading (0%)...");
                    podcaster.upload(new UploaderProgressListener()
                    {

                        public void updateProgress(long total, long uploaded)
                        {
                            double percent = uploaded/(double)total;
                            progress.setValue((int)(stage.get()+20*percent));
                            progressTitle.setText("Uploading (" + (int)(percent*100) + "%)...");
                        }
                    }, isDraft);
                    if(isCancelled.get())
                    {
                        return;
                    }
                    progress.setValue(stage.addAndGet(20));

                    
                    progressTitle.setText("Publishing...");
                    podcaster.publish(isDraft);
                    isDone.set(true);
                    progressTitle.setText("Podcasting: Done!");
                    progress.setValue(stage.addAndGet(20));
                }
                catch(Exception e)
                {
                    JOptionPane.showMessageDialog(dialog, "An unexpected error occurred: \n\t "+e.getLocalizedMessage(), "Podcast Error", JOptionPane.ERROR_MESSAGE);
                }
                finally
                {
                    dialog.dispose();
                    if(isDone.get())
                    {
                        saveLastPromptValues();
                        //show quit dialog
                        int retval = JOptionPane.showConfirmDialog(dialog, "The podcast has been successfully uploaded\nwould you like to quit?", "Podcast Complete!", JOptionPane.YES_NO_OPTION);
                        if(retval==JOptionPane.YES_OPTION)
                        {
                            System.exit(0);
                        }                       
                    }
                }
            }
        };
        t.start();
        dialog.setVisible(true);
    }
    
    private File copyToLocalTempFile() throws IOException
    {
        File tempSourceFile = File.createTempFile("NC_PODCAST", ".MP3");
        tempSourceFile.deleteOnExit();
        InputStream is = new FileInputStream(mp3File);
        OutputStream os = new FileOutputStream(tempSourceFile);
        byte[] bytes = new byte[1024];
        int bread = -1;
        while((bread=is.read(bytes))>=0)
        {
            os.write(bytes, 0, bread);
        }
        os.close();
        is.close();
        return tempSourceFile;
    }
    
    private void doBrowse()
    {        

        FileDialog d = new FileDialog(this);
        d.setTitle("Select Podcast File");
        d.setMode(FileDialog.LOAD);
        d.setVisible(true);

        if(d.getFile()!=null)
        {
            mp3File = new File(d.getDirectory(), d.getFile());
            try
            {
                JaudioID3Tagger tagger = new JaudioID3Tagger(mp3File);
                lengthField.setText(tagger.getLengthInfo());
                samplerateField.setText(tagger.getSampleRateInfo());
                filenameField.setText(mp3File.getName());
                sermonTitleField.setText(tagger.getTitle());
                publishButton.setEnabled(true);
            }
            catch (IOException e)
            {
                mp3File=null;
            }
        }
    }
    
    private void updateContext(Map<String, String> ctx) throws Exception
    {   
        Map<String, String> newCtx = getContext();
        newCtx.putAll(ctx);
        Properties prefs = new Properties();
        
        Map<String, String> retval = new HashMap<String, String>(prefs.size());
        for(Map.Entry<String, String> e : newCtx.entrySet())
        {
            prefs.put(e.getKey(),e.getValue());
        }
        //pref not to store.
        prefs.remove("blogger_appid");
        if(!prefsDir.exists())
        {
            prefsDir.mkdir();
        }   
        OutputStream os = new FileOutputStream(prefsFile);
        prefs.store(os, "");

    }
    private Map<String, String> getContext()
    {
        Properties prefs = new Properties();
        if(prefsFile.exists())
        {
            try
            {
                prefs.load(new FileInputStream(prefsFile));
            }
            catch (Exception e)
            {
                prefs.clear();
            }
        }
        
        Map<String, String> retval = getFactoryContext();
        for(Map.Entry<Object, Object> e : prefs.entrySet())
        {
            retval.put(e.getKey().toString(),e.getValue().toString());
        }
        
        return retval;
    }
   
    private void loadLastPromptValues()
    {
        Properties prompts = new Properties();
        if(promptFile.exists())
        {
            try
            {
                prompts.load(new FileInputStream(promptFile));
            }
            catch (Exception e)
            {
                return;
            }
        }
        seriesTitleField.setText(prompts.getProperty("seriesTitle", ""));
        boolean isSeriesValue = Boolean.parseBoolean(prompts.getProperty("isSeries", Boolean.FALSE.toString()));
        
        if(isSeriesValue!=isSeries.isSelected())
        {
            isSeries.doClick();
        }
        speakerField.setText(prompts.getProperty("speaker", ""));
        String type = prompts.getProperty("type");
        if(type!=null)
        {
            for(int typeIdx=0; typeIdx<publishTypes.length; typeIdx++)
            {
                if(type.equals(publishTypes[typeIdx]))
                {
                    typeList.setSelectedIndex(typeIdx);
                }
            }
        }
    }

    private void saveLastPromptValues()
    {
        Properties prompts = new Properties();
        prompts.setProperty("seriesTitle", seriesTitleField.getText());
        prompts.setProperty("isSeries", Boolean.toString(isSeries.isSelected()));
        prompts.setProperty("speaker", speakerField.getText());
        prompts.setProperty("type", publishTypes[typeList.getSelectedIndex()]);
        try
        {
            if(!prefsDir.exists())
            {
                prefsDir.mkdir();
            }   
            prompts.store(new FileOutputStream(promptFile), "last prompt values");
        }
        catch (Exception e)
        {
            return;
        }
    }

    
    
    private Map<String, String> getFactoryContext()
    {
        Map<String, String> ctx = new HashMap<String,String>();
        String testBloggerBlogId="8422928620011639430";
        String liveBloggerBlogId="7353461746210490089";
        ctx.put(FTP_SERVER_CTX_NAME,"ecbiz94.inmotionhosting.com");
        ctx.put(FTP_USER_CTX_NAME,"podcast@northchurchcolumbus.com");
        ctx.put(FTP_PASS_CTX_NAME,"KAMKOBkm2fLy");
        ctx.put(LAME_PATH_CTX_NAME, "/usr/local/bin/lame");
        ctx.put(BLOGGER_USER_CTX_NAME,"northchurchcolumbus.com@gmail.com");
        ctx.put(BLOGGER_PASS_CTX_NAME,"01172010");
//        ctx.put("blog_username","brett.humphreys@gmail.com");
//        ctx.put("blog_password","024816");
        ctx.put(BLOGGER_ID_CTX_NAME, liveBloggerBlogId);

        ctx.put("blogger_appid", "northchurchcolumbus-ncpodcaster-110");
        String urlPrefix="http://ecbiz94.inmotionhosting.com/~northc22/podcast/content/";
        ctx.put(URL_PREFIX_CTX_NAME, urlPrefix);
        return ctx;
    }
    
    public void showPreferencesDialog()
    {
        final Map<String, String> ctx = getContext();
        final JDialog prefs = new EscapableJDialog(this);
        prefs.setTitle("northChurch Podcaster Preferences");
        Container contentPane = prefs.getContentPane();
        contentPane.setLayout(new BorderLayout());
        JPanel promptingPane = new JPanel();
        promptingPane.setLayout(new GridBagLayout());

        final JButton prefsOKButton = new JButton("OK");
        final JButton prefsCancelButton = new JButton("Cancel");
        final JTextField prefsFtpServer=new JTextField(20);
        final JTextField prefsFtpUser=new JTextField(20);
        final JPasswordField prefsFtpPass=new JPasswordField(20);
        final JTextField prefsBloggerUser=new JTextField(20);
        final JPasswordField prefsBloggerPass=new JPasswordField(20);
        final JTextField prefsBlogId=new JTextField(20);
        final JTextField prefsUrlPrefix = new JTextField(20);
        final JTextField prefsLamePath = new JTextField(20);

        prefsFtpServer.setText(ctx.get(FTP_SERVER_CTX_NAME));
        prefsFtpUser.setText(ctx.get(FTP_USER_CTX_NAME));
        prefsFtpPass.setText(ctx.get(FTP_PASS_CTX_NAME));
        prefsBloggerUser.setText(ctx.get(BLOGGER_USER_CTX_NAME));
        prefsBlogId.setText(ctx.get(BLOGGER_ID_CTX_NAME));
        prefsBloggerPass.setText(ctx.get(BLOGGER_PASS_CTX_NAME));
        prefsUrlPrefix.setText(ctx.get(URL_PREFIX_CTX_NAME));
        prefsLamePath.setText(ctx.get(LAME_PATH_CTX_NAME));
        
        GridBagConstraints c = new GridBagConstraints();
        c.anchor=GridBagConstraints.WEST;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridwidth=1;
        c.gridy=0;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("FTP Username:"),c);

        c.gridx++;
        c.weightx=1;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsFtpUser, c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("FTP Password:"),c);

        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsFtpPass,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("FTP Server:"),c);

        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsFtpServer,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("MP3 FTP URL Prefix:"),c);

        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsUrlPrefix,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("Blog Username:"),c);

        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsBloggerUser,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("Blog Password:"),c);

        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsBloggerPass,c);
        

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("Blog ID"),c);

        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsBlogId,c);

        c.gridy++;
        c.gridx=0;
        c.weightx=0;
        c.insets = new Insets(12, 8, 0, 8);
        promptingPane.add(new JLabel("LAME Path:"),c);

        c.gridx++;
        c.weightx=0;
        c.insets = new Insets(8, 0, 0, 8);
        promptingPane.add(prefsLamePath,c);

        
        JPanel buttonPane = new JPanel();
        buttonPane.setLayout(new GridBagLayout());
        GridBagConstraints c1 = new GridBagConstraints();
        
        c1.gridx=0;
        c1.gridy=0;
        c1.insets = new Insets(8, 0, 8, 8);
        c1.fill = GridBagConstraints.NONE;
        buttonPane.add(prefsCancelButton,c1);
        c1.gridx++;
        buttonPane.add(prefsOKButton,c1);
        
        c.gridy++;
        c.gridx=0;
        c.gridwidth=2;
        c.weightx=1;
        c1.insets = new Insets(0,0,0,0);
        c.fill = GridBagConstraints.NONE;
        c.anchor=GridBagConstraints.EAST;        
        promptingPane.add(buttonPane, c);
        contentPane.add(promptingPane, BorderLayout.CENTER);
        prefs.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        prefs.getRootPane().setDefaultButton(prefsOKButton);
        prefs.pack();
        prefs.setResizable(false);

        prefsCancelButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                prefs.dispose();
            }
        });
        
        prefsOKButton.addActionListener(new ActionListener()
        {
            
            public void actionPerformed(ActionEvent e)
            {
                ctx.put(FTP_SERVER_CTX_NAME, prefsFtpServer.getText());
                ctx.put(FTP_USER_CTX_NAME, prefsFtpUser.getText());
                ctx.put(FTP_PASS_CTX_NAME, new String(prefsFtpPass.getPassword()));
                ctx.put(BLOGGER_ID_CTX_NAME, prefsBlogId.getText());
                ctx.put(BLOGGER_PASS_CTX_NAME, new String(prefsBloggerPass.getPassword()));
                ctx.put(BLOGGER_USER_CTX_NAME, prefsBloggerUser.getText());
                ctx.put(URL_PREFIX_CTX_NAME, prefsUrlPrefix.getText());
                ctx.put(LAME_PATH_CTX_NAME, prefsLamePath.getText());
                try
                {
                    updateContext(ctx);
                }
                catch (Exception e1)
                {
                    JOptionPane.showMessageDialog(prefs, e1.getMessage(), "Error Saving Preferences", JOptionPane.ERROR_MESSAGE);
                }
                prefs.dispose();
            }
        });
        
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        int X = (screen.width / 2) - (prefs.getWidth() / 2); // Center horizontally.
        int Y = (screen.height / 2) - (prefs.getHeight() / 2); // Center vertically.
        prefs.setLocation(X, Y);
        prefs.setVisible(true);
    }
}
